﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MARZ_Script.analysis;
using MARZ_Script.node;

namespace SableCC15.CodeGeneration
{
    //TODO Clean up this class! There should be no Emit logic inside this class!
    public class CodeGenerator : MARZ_Script.analysis.DepthFirstAdapter
    {

        public static string FileName { get; set; }
        public override void CaseAProg(MARZ_Script.node.AProg node)
        {
            Utility.Emit("using System;");
            Utility.Emit("using System.Collections.Generic;");
            Utility.Emit("using System.Linq;");
            Utility.Emit("using System.Text;");
            Utility.Emit("using SFML.Audio;" +
                "using SFML.Graphics;" +
                "using SFML.System;" +
                "using SFML.Window;");
            Utility.Emit("namespace MarzTargetCode {");

            Utility.Emit("public class " + FileName + "{");
            Utility.Emit("RenderWindow window;" +
                "public Target(RenderWindow rw){" +
                "this.window = rw; }");
            Utility.EmitComment("Templates");
            node.GetTemplates().Apply(new TemplateCodeGen());
            Utility.EmitComment("END Templates");
            Utility.Emit("public void GameLoop(){");
            Utility.EmitComment("Start");
            node.GetStart().Apply(this);
            Utility.EmitComment("END Start");
            Utility.Emit("while(window.IsOpen){");
            Utility.EmitComment("Update");
            node.GetUpdate().Apply(this);
            Utility.EmitComment("END Update");
            Utility.EmitComment("Draw");
            Utility.Emit("window.Clear();");
            node.GetDraw().Apply(this);
            Utility.EmitComment("END Draw");
            Utility.Emit("window.Display();");
            Utility.Emit("window.Closed+=(sender, e) => window.Close();");
            Utility.Emit("window.DispatchEvents();");
            Utility.Emit("}");
            Utility.Emit("}");
            Utility.EmitComment("Functions");
            node.GetFunctions().Apply(this);
            Utility.EmitComment("END Functions");
            Utility.Emit("}");
            Utility.Emit("}");
        }

        public override void CaseAStart(MARZ_Script.node.AStart node)
        {
            node.GetStartFunc().Apply(new DeclarationCodeGen());
            node.GetBodyList().Apply(this);
        }

        public override void CaseAUpdate(MARZ_Script.node.AUpdate node)
        {
            node.GetUpdateFunc().Apply(new DeclarationCodeGen());
            node.GetBodyList().Apply(this);
        }

        public override void CaseADraw(MARZ_Script.node.ADraw node)
        {
            node.GetDrawFunc().Apply(new DeclarationCodeGen());
            node.GetBodyList().Apply(this);

        }
        public override void CaseADeclBody(MARZ_Script.node.ADeclBody node)
        {
            node.GetVarDecl().Apply(new DeclarationCodeGen());
        }
        public override void CaseAExprBody(MARZ_Script.node.AExprBody node)
        {
            node.GetExpression().Apply(new ExpressionCodeGen());
            Utility.Emit(";");
        }

        public override void CaseAReturnBody(MARZ_Script.node.AReturnBody node)
        {
            Utility.Emit(node.GetTReturn().ToString().ToLower().Trim() + " ");
            node.GetExpressionOpt().Apply(new ExpressionCodeGen());
            Utility.Emit(";");
        }

        public override void CaseAFunc(MARZ_Script.node.AFunc node)
        {
            string id = node.GetId().ToString().Trim();

            node.GetFuncReturn().Apply(this);
            //Utility.Emit(returntype + " ");
            Utility.Emit(id);
            Utility.Emit(node.GetOParenth().Text);
            node.GetParamsRecursive().Apply(new DeclarationCodeGen());
            Utility.Emit(node.GetCParenth().Text);
            Utility.Emit("{");
            node.GetBodyList().Apply(this);
            node.GetEnd().Apply(this);
        }

        public override void CaseATypeFuncReturn(ATypeFuncReturn node)
        {
            if (node.GetType().ToString().Trim() == "coord")
                Utility.Emit("Coord" + " ");
            else if (node.GetType().ToString().Trim() == "float")
                Utility.Emit("double" + " ");
            else
                Utility.Emit(node.GetType().ToString().Trim() + " ");
        }
        public override void CaseAVoidFuncReturn(AVoidFuncReturn node)
        {
            Utility.Emit("void ");
        }

        public override void CaseACstructBody(MARZ_Script.node.ACstructBody node)
        {
            node.GetCStruct().Apply(new CodeGeneration.ControlStructCodeGen());
        }

        //Everything with capital letter is missing translation
        //DO NOT CHANGE THE ORDER OF THE KEYS. its what the translation depends on
        //http://www.sfml-dev.org/documentation/2.2/classsf_1_1Keyboard.php
        enum Keys
        {
            a = 0, b, c,
            d, e, f, g,
            h, i, j, k,
            l, m, n, o,
            p, q, r, s,
            t, u, v, w,
            x, y, z, d0, //d = digit
            d1, d2, d3, d4,
            d5, d6, d7, d8,
            d9, escape, lctrl, lshift,
            alt, lsystem, rctrl, rshift,
            altgr, rsystem, Menu, LBracket,
            RBracket, SemiColon, comma, period,
            Quote, Slash, BackSlash, Tilde,
            Equal, Dash, Space, Return,
            BackSpace, Tab, pageup, pagedown,
            end, home, insert, delete,
            nadd, nsubtract, nmultiply, ndivide,
            leftarrow, rightarrow, uparrow, downarrow,
            n0, n1, n2, n3,
            n4, n5, n6, n7,
            n8, n9, f1, f2,
            f3, f4, f5, f6,
            f7, f8, f9, f10,
            f11, f12, printscreen, scrolllock,
            pause, U_Pause, KeyCount
        };
        public override void CaseAAddKeyDefinationBody(AAddKeyDefinationBody node)
        {
            try
            {
                string key = node.GetTKey().Text.Replace("Key", string.Empty).Replace(":", string.Empty).ToLower();
                int k = (int)Enum.Parse(typeof(Keys), key);
                Utility.Emit("if (Keyboard.IsKeyPressed((Keyboard.Key)" + k + "))");
                Utility.Emit("{");
                node.GetConditionalExp().Apply(new ExpressionCodeGen());
                Utility.Emit(";");
                Utility.Emit("}");
            }
            catch (ArgumentException ae)
            {
                Utility.EmitComment("Unkown key, " + node.GetTKey().Text);
                Console.WriteLine("\n***Unkown key, cant translate " + node.GetTKey().Text);
                Console.WriteLine();
            }
        }
        public override void CaseTEnd(MARZ_Script.node.TEnd node)
        {
            Utility.Emit("}");
        }
    }
}
